library IEEE;
use IEEE.std_logic_1164.all;
entity if_tx is
	port(
		data_tx: out std_logic_vector(15 downto 0);
		cha_fifo_data: in std_logic_vector(15 downto 0);
		chb_fifo_data: in std_logic_vector(15 downto 0);
		la_fifo_data: in std_logic_vector(15 downto 0);
		cha_fifo_rdreq: out std_logic;
		chb_fifo_rdreq: out std_logic;
		la_fifo_rdreq: out std_logic;
		cha_fifo_rdempty: in std_logic;
		chb_fifo_rdempty: in std_logic;
		la_fifo_rdempty: in std_logic;
		fifo_sel: in std_logic_vector(2 downto 0);
		flagb: in std_logic; --EP2 full,active low
		slwr: out std_logic;
		pktend: out std_logic;
		ifclk: in std_logic;
		rst: in std_logic;
		packet_header: in std_logic_vector(31 downto 0);
		start_tx: in std_logic
	);
end if_tx;
architecture arch_if_tx of if_tx is
type states is (idle,head_1,head_2,head_done,stat_sync,body_wait,body_write,body_done);
signal pr_state,nx_state: states;
signal fifo_data:std_logic_vector(15 downto 0);
signal fifo_rdreq: std_logic;
signal fifo_rdempty: std_logic;
signal fine_counter_en,fine_counter_expired:std_logic;
component counter is
    generic (max : natural);
	port ( enable: in std_logic;
		   current_val: out natural;
		   expired: out std_logic;
		   clk:in std_logic;
		   rst: in std_logic
	);
end component;
begin
	fine_counter: counter generic map (max => 511) port map (
		enable => fine_counter_en,
		current_val => open,
		expired => fine_counter_expired,
		clk => ifclk,
		rst => rst);
--    base_counter: counter generic map (max => 7) port map (
--        enable => base_counter_en,
--        current_val => open,
--        expired => base_counter_expired,
--        clk => ifclk,
--        rst => rst);
	cha_fifo_rdreq <= fifo_rdreq when fifo_sel = "001" else '0';
	chb_fifo_rdreq <= fifo_rdreq when fifo_sel = "010" else '0';
	la_fifo_rdreq <= fifo_rdreq when fifo_sel = "100" else '0';
	fifo_rdreq <= '1' when nx_state = body_write else '0';
	fine_counter_en <= '1' when pr_state = body_write else '0';
	with fifo_sel select
		fifo_rdempty 	<= cha_fifo_rdempty when "001",
					 chb_fifo_rdempty when "010",
					 la_fifo_rdempty when "100",
					 '0' when others;
	with fifo_sel select
		fifo_data 	<= cha_fifo_data when "001",
				chb_fifo_data when "010",
				la_fifo_data when "100",
				(others => '0') when others;	
	process(ifclk,rst)
	begin
		if(rst = '1')then
			pr_state <= idle;
		elsif(ifclk = '1' and ifclk'event) then
			pr_state <= nx_state;
		end if;
	end process;
	process(ifclk,rst)
	begin
		if(rst = '1')then
			pktend <= '1';
		elsif(ifclk = '1' and ifclk'event) then
			if(nx_state = head_done or nx_state = body_done) then
				pktend <= '0';
			else
				pktend <= '1';
			end if;
		end if;
	end process;
	process(ifclk,rst)
	begin
		if(rst = '1')then
			slwr <= '1';
			data_tx <= (others => '0');
		elsif(ifclk = '1' and ifclk'event) then
			case nx_state is
				when head_1 =>
					data_tx <= packet_header(15 downto 0);
					slwr <= '0';
				when head_2 =>
					data_tx <= packet_header(31 downto 16);
				when head_done =>
					slwr <= '1';
				when body_wait =>
					slwr <= '1';
				when body_write =>
					slwr <= '0';
					data_tx <= fifo_data;
				when body_done =>
					slwr <= '1';
				when others =>
					null;
			end case;
		end if;
	end process;
	process(pr_state,start_tx,fine_counter_expired,fifo_rdempty,flagb)
	begin
		case pr_state is
			when idle =>
				if(start_tx = '1') then
					nx_state <= head_1;
				else
					nx_state <= pr_state;
				end if;
			when head_1 =>
				nx_state <= head_2;
			when head_2 =>
				nx_state <= head_done;
			when head_done =>
				nx_state <= stat_sync;
            when stat_sync =>
                nx_state <= body_wait;
			when body_wait =>
				if(flagb = '1') then
					nx_state <= body_write;
				else
					nx_state <= pr_state;
				end if;
			when body_write =>
				if(fifo_rdempty = '1') then
					nx_state <= body_done;
				elsif(fine_counter_expired = '1') then
					nx_state <= stat_sync;
				else
					nx_state <= pr_state;
				end if;
			when body_done =>
				nx_state <= idle;
		end case;
	end process;
end arch_if_tx;